package opn.srn.command.convertor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import opn.srn.command.Command;
import opn.srn.command.ICommand;
import opn.srn.common.IMessage;
import opn.srn.common.script.MessageBinding;
import opn.srn.common.script.ScriptExecutorFactory;
import opn.srn.common.script.ScriptInfo;
import opn.srn.event.EventConstants;
import opn.srn.event.IEvent;

public class ConvertorCommand extends Command {

	public static final String NAME = "convertor";

	public List<ConvertAction> convertActions = new ArrayList<ConvertAction>();

	public ConvertorCommand() {
		super(NAME);
	}

	@Override
	public void load(Map<String, String> parameters) throws Exception {
		String fieldList = parameters.get("fields");
		if (fieldList == null) {
			throw new Exception("fields parameter missing for convertor command...");
		}

		String[] fields = fieldList.split(",");
		for (int index = 0; index < fields.length; index++) {
			ConvertAction convertAction = getConvertAction(fields[index], parameters);
			if (convertAction != null) {
				convertActions.add(convertAction);
			}
		}
	}

	private ConvertAction getConvertAction(String fieldInfo, Map<String, String> parameters) throws Exception {
		fieldInfo = fieldInfo.trim();
		if (fieldInfo.isEmpty()) {
			return null;
		}

		char actionType = fieldInfo.charAt(0);
		if (actionType == '-' /* delete action */) {
			if (fieldInfo.length() == 1) {
				throw new Exception("fields parameter contains just '-' in convertor command");
			}
			if (fieldInfo.charAt(1) == '*') {
				return new ConvertAction(null, ConvertActionType.delete, null);
			} else {
				return new ConvertAction(fieldInfo.substring(1).trim(), ConvertActionType.delete, null);
			}
		} else {
			return new ConvertAction(fieldInfo, ConvertActionType.addOrReplace, loadScriptInfo(fieldInfo, parameters));
		}
	}

	private ScriptInfo loadScriptInfo(String fieldInfo, Map<String, String> parameters) throws Exception {
		String code = parameters.get(fieldInfo);
		if (code == null || code.isEmpty()) {
			throw new Exception(fieldInfo + " attribute missing in convertor command");
		}

		return new ScriptInfo("groovy", code);
	}

	@Override
	public void onEvent(ICommand<?> source, IEvent event) throws Exception {
		switch (event.getType()) {
		case EventConstants.CMD_START: {
			break;
		}
		case EventConstants.CMD_DATA: {
			Object data = event.getData();
			if (data instanceof IMessage) {
				IMessage message = (IMessage) data;
				try {
					IMessage cloneInstance = (IMessage) message.clone();
					event.setData(convert(cloneInstance));
					fireEvent(source, event);
				} finally {
					event.setData(message);
				}
				return;
			}
		}
		case EventConstants.CMD_FINISH: {
			break;
		}
		}
		fireEvent(source, event);
	}

	private IMessage convert(IMessage message) throws Exception {
		MessageBinding binding = new MessageBinding(message);
		for (ConvertAction action : convertActions) {
			ConvertActionType actionType = action.getType();
			if (actionType.equals(ConvertActionType.delete)) {
				String fieldName = action.getFieldName();
				if (fieldName != null) {
					message.remove(fieldName);
				} else {
					message.clear();
				}
			} else if (actionType.equals(ConvertActionType.addOrReplace)) {
				Object value = ScriptExecutorFactory.executeScript(action.getInfo(), binding);
				message.setData(action.getFieldName(), value);
			}
		}
		return message;
	}

}
